package com.dubious.interview.euler.booleans;

/**
 * A two-dimensional array-based implementation of {@link Booleans}.
 */
public class ArrayedBooleans implements Booleans
{
    boolean[][] booleanArrays;
    public long upperBound = 0L;
    public int arrayBoundary = Integer.MAX_VALUE;
    
    public ArrayedBooleans(long upperBound)
    {
        this.upperBound = upperBound;
        
        long numArrays = (upperBound / arrayBoundary) + 1;
        if(numArrays > Integer.MAX_VALUE)
        {
            throw new RuntimeException(
                    "Cannot create Booleans with upperBound of [" 
                    + upperBound +"] because it would require too many [" 
                    + numArrays + "] arrays.");
        }
        
        booleanArrays = new boolean[(int)numArrays][];
        for(int i = 0; i < numArrays - 1; i++)
        {
            booleanArrays[i] = new boolean[arrayBoundary];
        }
        booleanArrays[(int)numArrays - 1] = new boolean[(int)upperBound % arrayBoundary];
    }
    
    @Override
    public void set(long index, boolean value)
    {
        if(index > upperBound)
        {
            throw new IndexOutOfBoundsException(
                    "index [" + index + "] is greater than upper bound [" + upperBound + "]");
        }
        
        // we know it is ok to cast the get parameter to an int because we checked in the 
        // constructor that we would have number of arrays less than Integer.MAX_VALUE.
        // we know it is ok to cast the array lookup parameter to int because arrayBoundary
        // is an int
        booleanArrays[(int)(index / arrayBoundary)][(int)(index % arrayBoundary)] = value;
    }
    
    @Override
    public boolean get(long index)
    {
        return booleanArrays[(int)(index / arrayBoundary)][(int)(index % arrayBoundary)];
    }
}